<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha256-wiz7ZSCn/btzhjKDQBms9Hx4sSeUYsDrTLg7roPstac=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css" integrity="sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/green/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"sumumm.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.19.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":true,"height":300},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="kobject是什么？kset是啥？ktype是啥？有啥用？若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:type" content="article">
<meta property="og:title" content="LV06-04-linux设备模型-02-kobject相关的数据结构">
<meta property="og:url" content="https://sumumm.github.io/post/5eede1d3.html">
<meta property="og:site_name" content="苏木">
<meta property="og:description" content="kobject是什么？kset是啥？ktype是啥？有啥用？若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105194754452.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105142410897.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105151716578.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105154536844.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105161224342.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105153000146.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105153345305.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105164847750.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105154248298.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105202747415.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105203726480.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105200924853.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105224309104.png">
<meta property="article:published_time" content="2025-01-05T14:46:49.000Z">
<meta property="article:modified_time" content="2025-06-13T16:25:57.050Z">
<meta property="article:author" content="苏木">
<meta property="article:tag" content="LV06-驱动开发">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105194754452.png">


<link rel="canonical" href="https://sumumm.github.io/post/5eede1d3.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":"","permalink":"https://sumumm.github.io/post/5eede1d3.html","path":"post/5eede1d3.html","title":"LV06-04-linux设备模型-02-kobject相关的数据结构"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>LV06-04-linux设备模型-02-kobject相关的数据结构 | 苏木</title>
  








    <script src="/js/browser_tools_disable.js"></script>

  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<!-- hexo injector head_end start --><link rel="stylesheet" href="https://unpkg.com/hexo-next-tags-plus@latest/lib/tag_plus.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">苏木</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">我的学习之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>苏木的家</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类页<span class="badge">42</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档页<span class="badge">673</span></a></li><li class="menu-item menu-item-flink"><a href="/flink/" rel="section"><i class="fa fa-link fa-fw"></i>友人帐</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于我</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E6%A6%82%E8%BF%B0"><span class="nav-text">一、概述</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-kobject%E3%80%81kset%E5%92%8Cktype"><span class="nav-text">1. kobject、kset和ktype</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E6%9C%89%E4%BB%80%E4%B9%88%E5%85%B3%E7%B3%BB%EF%BC%9F"><span class="nav-text">2. 有什么关系？</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81kobject"><span class="nav-text">二、kobject</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E8%83%8C%E6%99%AF"><span class="nav-text">1. 背景</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-kobject%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="nav-text">2. kobject是什么？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-kobject%E8%83%BD%E5%81%9A%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="nav-text">3. kobject能做什么？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-%E5%9C%A8%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84%E8%A1%A8%E7%8E%B0%EF%BC%9F"><span class="nav-text">4. 在系统中的表现？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-kobject%E6%9C%BA%E5%88%B6"><span class="nav-text">5. kobject机制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6-%E7%9B%B8%E5%85%B3API"><span class="nav-text">6. 相关API</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#6-1-kobject%E4%BD%BF%E7%94%A8%E6%B5%81%E7%A8%8B"><span class="nav-text">6.1 kobject使用流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#6-2-kobject%E7%9A%84%E5%88%86%E9%85%8D%E5%92%8C%E9%87%8A%E6%94%BE"><span class="nav-text">6.2 kobject的分配和释放</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#6-2-1-%E9%80%9A%E8%BF%87kmalloc%E8%87%AA%E8%A1%8C%E5%88%86%E9%85%8D"><span class="nav-text">6.2.1 通过kmalloc自行分配</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#6-2-1-1-kobject-init"><span class="nav-text">6.2.1.1 kobject_init()</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#6-2-1-2-kobject-add"><span class="nav-text">6.2.1.2 kobject_add()</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#6-2-1-3-kobject-init-and-add"><span class="nav-text">6.2.1.3 kobject_init_and_add()</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#6-2-2-%E4%BD%BF%E7%94%A8kobject-create-%E5%88%9B%E5%BB%BA"><span class="nav-text">6.2.2 使用kobject_create()创建</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#6-2-2-1-kobject-create"><span class="nav-text">6.2.2.1 kobject_create()</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#6-2-2-2-kobject-add"><span class="nav-text">6.2.2.2 kobject_add()</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#6-2-2-3-kobject-create-and-add"><span class="nav-text">6.2.2.3 kobject_create_and_add()</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#6-3-kobject%E5%BC%95%E7%94%A8%E8%AE%A1%E6%95%B0%E7%9A%84%E5%8A%A0%E5%87%8F"><span class="nav-text">6.3 kobject引用计数的加减</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#6-3-1-kobject-get"><span class="nav-text">6.3.1 kobject_get()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#6-3-2-kobject-put"><span class="nav-text">6.3.2 kobject_put()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#6-3-3-kobject-release"><span class="nav-text">6.3.3 kobject_release()</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#7-%E5%88%9B%E5%BB%BAkobject-demo"><span class="nav-text">7. 创建kobject demo</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#7-1-demo%E6%BA%90%E7%A0%81"><span class="nav-text">7.1 demo源码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#7-2-%E5%BC%80%E5%8F%91%E6%9D%BF%E9%AA%8C%E8%AF%81"><span class="nav-text">7.2 开发板验证</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81kset"><span class="nav-text">三、kset</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-kset%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="nav-text">1. kset是什么？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-kset%E5%92%8Ckobject%E7%9A%84%E5%85%B3%E7%B3%BB"><span class="nav-text">2. kset和kobject的关系</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E7%9B%B8%E5%85%B3API"><span class="nav-text">3. 相关API</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-4-kset%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96%E3%80%81%E6%B3%A8%E5%86%8C"><span class="nav-text">3.4 kset的初始化、注册</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-1-kset-init"><span class="nav-text">3.4.1 kset_init()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-2-kset-register"><span class="nav-text">3.4.2 kset_register()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-3-kset-unregister"><span class="nav-text">3.4.3 kset_unregister()</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-4-4-kset-create-and-add"><span class="nav-text">3.4.4 kset_create_and_add()</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-%E5%88%9B%E5%BB%BAkset-demo"><span class="nav-text">4. 创建kset demo</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-demo%E6%BA%90%E7%A0%81"><span class="nav-text">4.1 demo源码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-%E5%BC%80%E5%8F%91%E6%9D%BF%E9%AA%8C%E8%AF%81"><span class="nav-text">4.2 开发板验证</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81%E5%BC%95%E7%94%A8%E8%AE%A1%E6%95%B0%E5%99%A8"><span class="nav-text">四、引用计数器</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E4%BB%80%E4%B9%88%E6%98%AF%E5%BC%95%E7%94%A8%E8%AE%A1%E6%95%B0%E5%99%A8%EF%BC%9F"><span class="nav-text">1. 什么是引用计数器？</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-kref-%E7%AE%80%E4%BB%8B"><span class="nav-text">2. kref 简介</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E7%9B%B8%E5%85%B3API-1"><span class="nav-text">3. 相关API</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-kref-init"><span class="nav-text">3.1 kref_init()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-kref-get"><span class="nav-text">3.2 kref_get() </span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-kref-put"><span class="nav-text">3.3 kref_put()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-4-refcount-set"><span class="nav-text">3.4 refcount_set()</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-kref-demo"><span class="nav-text">4. kref demo</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-demo%E6%BA%90%E7%A0%81-1"><span class="nav-text">4.1 demo源码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-%E5%BC%80%E5%8F%91%E6%9D%BF%E9%AA%8C%E8%AF%81-1"><span class="nav-text">4.2 开发板验证</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%94%E3%80%81ktype"><span class="nav-text">五、ktype</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-kobj-type%E6%98%AF%E4%BB%80%E4%B9%88"><span class="nav-text">1. kobj_type是什么</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-ktype%E4%B8%8Ekobject%E7%9A%84%E5%85%B3%E7%B3%BB"><span class="nav-text">2. ktype与kobject的关系</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-ktype-demo"><span class="nav-text">3. ktype demo</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-demo%E6%BA%90%E7%A0%81"><span class="nav-text">3.1 demo源码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-%E5%BC%80%E5%8F%91%E6%9D%BF%E9%AA%8C%E8%AF%81"><span class="nav-text">3.2 开发板验证</span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="苏木"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">苏木</p>
  <div class="site-description" itemprop="description">莫道桑榆晚，为霞尚满天</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">673</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">42</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">43</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/sumumm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sumumm" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://sumumm.github.io/post/5eede1d3.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="苏木">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="苏木">
      <meta itemprop="description" content="莫道桑榆晚，为霞尚满天">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="LV06-04-linux设备模型-02-kobject相关的数据结构 | 苏木">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          LV06-04-linux设备模型-02-kobject相关的数据结构
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2025-01-05 22:46:49" itemprop="dateCreated datePublished" datetime="2025-01-05T22:46:49+08:00">2025-01-05</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">嵌入式开发</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/" itemprop="url" rel="index"><span itemprop="name">02IMX6ULL平台</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">LV06-驱动开发</span></a>
        </span>
    </span>

  
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>11k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>41 分钟</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>kobject是什么？kset是啥？ktype是啥？有啥用？若笔记中有错误或者不合适的地方，欢迎批评指正😃。</p>
<span id="more"></span>

<!-- Photo: https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/ -->

<details class="folding-tag" blue><summary> 点击查看使用工具及版本 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" rowspan="5">PC端开发环境</td>        <td align="center" width=150px>Windows</td>        <td align="left">Windows11</td>    </tr>    <tr>        <td align="center">Ubuntu</td>        <td align="left">Ubuntu20.04.2的64位版本</td>      </tr>    <tr>        <td align="center">VMware® Workstation 17 Pro</td>        <td align="left">17.6.0 build-24238078</td>      </tr>    <tr>        <td align="center">终端软件</td>        <td align="left">MobaXterm(Professional Edition v23.0 Build 5042 (license))</td>    </tr>    <tr>        <td align="center">Win32DiskImager</td>        <td align="left">Win32DiskImager v1.0</td>      </tr>    <tr>        <td align="center" rowspan="3">Linux开发板环境</td>        <td align="center">Linux开发板</td>        <td align="left">正点原子 i.MX6ULL Linux 阿尔法开发板</td>      </tr>    <tr>        <td align="center">uboot</td>        <td align="left">NXP官方提供的uboot，使用的uboot版本为U-Boot 2019.04</td>      </tr>    <tr>        <td align="center">linux内核</td>        <td align="left">linux-4.19.71(NXP官方提供)</td>      </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看本文参考资料 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center">分类</td>        <td align="center">网址</td>        <td align="center">说明</td>    </tr>    <tr>        <td align="center" rowspan="5">官方网站</td>        <td align="left"><a href="https://www.arm.com/" target="_blank">https://www.arm.com/</a></td>        <td align="left">ARM官方网站，在这里我们可以找到Cotex-Mx以及ARMVx的一些文档</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxp.com.cn/" target="_blank">https://www.nxp.com.cn/ </a></td>        <td align="left">NXP官方网站</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxpic.org.cn/" target="_blank">https://www.nxpic.org.cn/</a></td><td align="left">NXP 官方社区</td>    </tr>    <tr>        <td align="left"><a href="https://u-boot.readthedocs.io/en/latest/" target="_blank">https://u-boot.readthedocs.io/en/latest/</a></td><td align="left">u-boot官网</td>    </tr>    <tr>        <td align="left"><a href="https://www.kernel.org/" target="_blank">https://www.kernel.org/</a></td><td align="left">linux内核官网</td>    </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看相关文件下载 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center">分类</td>        <td align="center">网址</td>        <td align="center">说明</td>    </tr>    <tr>        <td align="center" rowspan="3">NXP</td>        <td align="left"><a href="https://github.com/nxp-imx" target="_blank">https://github.com/nxp-imx</a></td>        <td align="left">NXP imx开发资源GitHub组织，里边会有u-boot和linux内核的仓库</td>    </tr>    <tr>        <td align="left"><a href="https://github.com/nxp-imx/linux-imx/releases/tag/v4.19.71" target="_blank">nxp-imx/linux-imx/releases/tag/v4.19.71</a></td>        <td align="left">NXP linux内核仓库tags中的v4.19.71</td>    </tr>    <tr>        <td align="left"><a href="https://github.com/nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0" target="_blank">nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0</a></td>        <td align="left">NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0</td>    </tr>    <tr>        <td align="center" rowspan="2">I.MX6ULL</td>        <td align="left"><a href="https://www.nxp.com.cn/docs/en/data-sheet/IMX6ULLIEC.pdf" target="_blank">i.MX 6ULL Applications Processors for Industrial Products</a></td>        <td align="left">I.MX6ULL 芯片手册（datasheet，可以在线查看）</td>    </tr>    <tr>        <td align="left"><a href="https://www.nxp.com.cn/webapp/Download?colCode=IMX6ULLRM&lang_cd=zh" target="_blank">i.MX 6ULL Applications ProcessorReference Manual</a></td>        <td align="left">I.MX6ULL 参考手册（下载后才能查看，需要登录NXP官网）</td>    </tr>    <tr>        <td align="center" rowspan="3">Source Code</td>        <td align="left"><a href="https://elixir.bootlin.com/linux/latest/source" target="_blank">https://elixir.bootlin.com/linux/latest/source</a></td>        <td align="left">linux kernel源码</td>    </tr>    <tr>        <td align="left"><a href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/?h=v4.19.71&id=e7d2672c66e4d3675570369bf20856296da312c4" target="_blank">kernel/git/stable/linux.git - Linux kernel stable tree</a></td>        <td align="left">linux kernel源码(官网,tag 4.19.71)</td>    </tr>    <tr>        <td align="left"><a href="https://elixir.bootlin.com/u-boot/latest/source" target="_blank">https://elixir.bootlin.com/u-boot/latest/source</a></td>        <td align="left">uboot源码</td>    </tr></table>
              </div>
            </details>

<p>kobject是Linux设备模型的基本单元，也是设备模型中最难理解的一部分，可参考内核文档 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/Documentation/kobject.txt">kobject.txt - Documentation&#x2F;kobject.txt</a>，内核文档好像是参考这个的：<a target="_blank" rel="noopener" href="https://lwn.net/Articles/51437/">The zen of kobjects LWN</a>。</p>
<h1 id="一、概述"><a href="#一、概述" class="headerlink" title="一、概述"></a><font size=3>一、概述</font></h1><h2 id="1-kobject、kset和ktype"><a href="#1-kobject、kset和ktype" class="headerlink" title="1. kobject、kset和ktype"></a><font size=3>1. kobject、kset和ktype</font></h2><p>这里先引出三个概念：kobject、kset和ktype，在开始这一节的学习前，先大概了解一下：</p>
<ul>
<li>kobject是基本数据类型，每个kobject都会在”&#x2F;sys&#x2F;“文件系统中以目录的形式出现。</li>
<li>kset是一个特殊的kobject（因此它也会在”&#x2F;sys&#x2F;“文件系统中以目录的形式出现），它用来集合相似的kobject（这些kobject可以是相同属性的，也可以不同属性的）。</li>
<li>ktype代表kobject（严格地讲，是包含了kobject的数据结构）的属性操作集合。由于通用性，多个kobject可能共用同一个属性操作集，因此把ktype独立出来了。每个kobject都会指定一个ktype（包括kset内嵌的kobject）。</li>
</ul>
<h2 id="2-有什么关系？"><a href="#2-有什么关系？" class="headerlink" title="2. 有什么关系？"></a><font size=3>2. 有什么关系？</font></h2><p>三者的关系大概如下：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105194754452.png" alt="image-20250105194754452" />

<ul>
<li>kset可批量管理kobject。</li>
<li>kset继承自kobject，且将一组kobject串连成一个链表进行统一管理。</li>
<li>kobject既可以通过parent指针找到上层kobject，也可以通过kset指针找到其上层kset。但上层kobject对象无法遍历到下层，所以较少使用。</li>
</ul>
<h1 id="二、kobject"><a href="#二、kobject" class="headerlink" title="二、kobject"></a><font size=3>二、kobject</font></h1><h2 id="1-背景"><a href="#1-背景" class="headerlink" title="1. 背景"></a><font size=3>1. 背景</font></h2><p>前面知道inux设备模型的核心是使用bus、class、device、driver四个核心数据结构，将大量不同功能的硬件设备及其驱动，以树状结构的形式，进行归纳、抽象，从而方便kernel的统一管理。而硬件设备的数量、种类是非常多的，这就决定了kernel中将会有大量的有关设备模型的数据结构。这些数据结构一定有一些共同的功能，需要抽象出来统一实现，否则就会不可避免的产生冗余代码。这就是kobject诞生的背景。</p>
<h2 id="2-kobject是什么？"><a href="#2-kobject是什么？" class="headerlink" title="2. kobject是什么？"></a><font size=3>2. kobject是什么？</font></h2><p>kobject(内核对象)是内核中抽象出来的通用对象模型， 用于表示内核中的各种实体。 kobject是一个结构体， 其中包含了一些描述该对象的属性和方法。 它提供了一种统一的接口和机制，用于管理和操作内核对象。</p>
<p>kobject结构体定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kobject.h#L65">kobject.h - include&#x2F;linux&#x2F;kobject.h -<em>struct kobject</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> &#123;</span></span><br><span class="line">	<span class="type">const</span> <span class="type">char</span>		*name;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>	<span class="title">entry</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kobject</span>		*<span class="title">parent</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kset</span>		*<span class="title">kset</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kobj_type</span>	*<span class="title">ktype</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kernfs_node</span>	*<span class="title">sd</span>;</span> <span class="comment">/* sysfs directory entry */</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kref</span>		<span class="title">kref</span>;</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> CONFIG_DEBUG_KOBJECT_RELEASE</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">delayed_work</span>	<span class="title">release</span>;</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">	<span class="type">unsigned</span> <span class="type">int</span> state_initialized:<span class="number">1</span>;</span><br><span class="line">	<span class="type">unsigned</span> <span class="type">int</span> state_in_sysfs:<span class="number">1</span>;</span><br><span class="line">	<span class="type">unsigned</span> <span class="type">int</span> state_add_uevent_sent:<span class="number">1</span>;</span><br><span class="line">	<span class="type">unsigned</span> <span class="type">int</span> state_remove_uevent_sent:<span class="number">1</span>;</span><br><span class="line">	<span class="type">unsigned</span> <span class="type">int</span> uevent_suppress:<span class="number">1</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<ul>
<li>name：该kobject的名称，通常用于在&#x2F;sys 目录下创建对应的目录。由于kobject添加到kernel时，需要根据名字注册到sysfs中，之后就不能再直接修改该字段。如果需要修改kobject的名字，需要调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L461">kobject_rename()</a> 接口，该接口会主动处理sysfs的相关事宜。</li>
<li>entry：用于将kobject加入到kset中的list_head，也就是将 kobject 链接到父 kobject 的子对象列表中， 以建立层次关系。</li>
<li>parent：指向parent kobject，以此形成层次结构（在sysfs就表现为目录结构）。</li>
<li>kset：指向包含该 kobject 的 kset(可以为NULL)， 用于进一步组织和管理 kobject。如果没有指定parent，则会把kset作为parent（kset是一个特殊的kobject）。</li>
<li>ktype：该kobject属于的kobj_type，描述 kobject 的属性和操作。每个kobject必须有一个ktype，否则kernel会提示错误。</li>
<li>sd：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kernfs.h#L129">kernfs_node</a> 类型，该kobject在sysfs中的层次结构。指向 sysfs 目录中对应的 kernfs_node， 用于访问和操作 sysfs 目录项。  </li>
<li>kref：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kref.h#L21">struct kref</a> 类型的变量，是一个可用于原子操作的引用计数。它用于对 kobject 进行引用计数， 确保在不再使用时能够正确释放资源。  </li>
<li>state_initialized：指示该kobject是否已经初始化，以在kobject的Init，Put，Add等操作时进行异常校验。</li>
<li>state_in_sysfs：指示该kobject是否已在sysfs中呈现，以便在自动注销时从sysfs中移除。</li>
<li>state_add_uevent_sent：记录是否已经向用户空间发送ADD uevent。</li>
<li>state_remove_uevent_sent：记录是否已经向用户空间发送REMOVE uevent，</li>
<li>uevent_suppress：如果该字段为1，则表示忽略所有上报的uevent事件。</li>
</ul>
<blockquote>
<p>uevent提供了“用户空间通知”的功能实现，通过该功能，当内核中有kobject的增删改等动作时，会通知用户空间。</p>
</blockquote>
<h2 id="3-kobject能做什么？"><a href="#3-kobject能做什么？" class="headerlink" title="3. kobject能做什么？"></a><font size=3>3. kobject能做什么？</font></h2><p>kobject主要提供如下功能：</p>
<p>（1）通过parent指针，可以将所有kobject以层次结构的形式组合起来。</p>
<p>（2）使用一个引用计数（reference count），来记录kobject被引用的次数，并在引用次数变为0时把它释放（这是kobject诞生时的唯一功能）。</p>
<p>（3）和sysfs虚拟文件系统配合，将每一个kobject及其特性，以文件的形式显示到用户空间（&#x2F;sys 目录下的那些东西）。</p>
<blockquote>
<p>Tips</p>
<p>（1）在Linux中，kobject几乎不会单独存在。它的主要功能，就是内嵌在一个大型的数据结构中，为这个数据结构提供一些底层的功能实现。</p>
<p>（2）Linux driver开发者，很少会直接使用kobject以及它提供的接口，而是使用构建在kobject之上的设备模型接口。</p>
</blockquote>
<h2 id="4-在系统中的表现？"><a href="#4-在系统中的表现？" class="headerlink" title="4. 在系统中的表现？"></a><font size=3>4. 在系统中的表现？</font></h2><p>每一个 kobject 都会对应系统&#x2F;sys&#x2F;下的一个目录：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105142410897.png" alt="image-20250105142410897" />

<p>目录又是有多个层次， 所以对应 kobject 的树状关系如下图所示：  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105151716578.png" alt="image-20250105151716578" />

<p>在 kobject 结构体中， parent 指针用于表示父 kobject， 从而建立了kobject 之间的层次关系， 类似于目录结构中的父目录和子目录的关系。 一个 kobject 可以有一个父 kobject 和多个子 kobject， 通过 parent 指针可以将它们连接起来形成一个层次化的结构，类似于目录结构中， 一个目录可以有一个父目录和多个子目录， 通过目录的路径可以表示目录之间的层次关系。 这种层次化的关系可以方便地进行遍历， 查找和管理， 使得内核对象能够按照层次关系进行组织和管理。 这种设计使得 kobject 的树状结构在内核中具有很高的灵活性和可扩展性。  </p>
<h2 id="5-kobject机制"><a href="#5-kobject机制" class="headerlink" title="5. kobject机制"></a><font size=3>5. kobject机制</font></h2><p>kobject的核心功能是：保持一个引用计数，当该计数减为0时，自动释放kobject所占用的meomry空间。这就决定了kobject必须是动态分配的，因为只有这样才能动态释放。</p>
<p>kobject大多数的使用场景，是内嵌在大型的数据结构中（如kset、device_driver等），因此这些大型的数据结构，也必须是动态分配、动态释放的。</p>
<p>那么释放的时机是什么呢？是内嵌的kobject释放时。但是kobject的释放是由kobject模块自动完成的（在引用计数为0时），那么怎么一并释放包含自己的大型数据结构呢？</p>
<p>这时kobj_type就派上用场了。因为kobj_type中的release回调函数负责释放kobject（甚至是包含kobject的数据结构）的内存空间。</p>
<p>那么kobj_type及其内部函数，是由谁实现呢？是由上层数据结构所在的模块！因为只有它才清楚kobject嵌在哪个数据结构中，并通过kobject指针以及自身的数据结构类型，利用函数宏containerof找到需要释放的上层数据结构的指针，然后释放它。</p>
<p>所以，每一个内嵌kobject的数据结构，例如kset、device、device_driver等等，都要实现一个kobj_type，并定义其中的回调函数。同理，sysfs相关的操作也一样，必须经过kobj_type的中转，因为sysfs看到的是kobject，而真正的文件操作的主体，是内嵌kobject的上层数据结构！</p>
<p>kobject是面向对象的思想在Linux kernel中的极致体现，但C语言的优势却不在这里，所以Linux kernel需要用比较巧妙的手段去实现它。</p>
<blockquote>
<p>这里出现的kobj_type、kset、引用计数等相关概念后面都会了解到的。</p>
</blockquote>
<h2 id="6-相关API"><a href="#6-相关API" class="headerlink" title="6. 相关API"></a><font size=3>6. 相关API</font></h2><h3 id="6-1-kobject使用流程"><a href="#6-1-kobject使用流程" class="headerlink" title="6.1 kobject使用流程"></a><font size=3>6.1 kobject使用流程</font></h3><ul>
<li>kobject大多数情况下（有一种例外，下面会提到）会嵌在其它数据结构中使用，其使用流程如下：</li>
</ul>
<p>（1）定义一个struct kset类型的指针，并在初始化时为它分配空间，添加到内核中;</p>
<p>（2）根据实际情况，定义内嵌有kobject的自己所需的数据结构原型；</p>
<p>（3）定义一个适合自己的kobj_type，并实现其中回调函数release；</p>
<p>（4）在需要使用到包含kobject的数据结构时，动态分配该数据结构，并分配kobject空间，添加到内核中；</p>
<p>（5）每一次引用数据结构时，调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L603">kobject_get()</a> 接口增加引用计数；引用结束时，调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L696">kobject_put()</a> 接口，减少引用计数；</p>
<p>（6）当引用计数为0时，kobject模块会自动调用kobj_type所提供的release接口，释放上层数据结构以及kobject的内存空间。</p>
<ul>
<li>有一种例外就是：开发者只需要在sysfs中创建一个目录，而不需要其它的kset、kobj_type的操作。这时可以直接调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L748">kobject_create_and_add()</a> 接口，分配一个kobject结构并把它添加到内核中。</li>
</ul>
<h3 id="6-2-kobject的分配和释放"><a href="#6-2-kobject的分配和释放" class="headerlink" title="6.2 kobject的分配和释放"></a><font size=3>6.2 kobject的分配和释放</font></h3><p>前面提到kobject必须动态分配，而不能静态定义或者位于堆栈之上，它的分配方法有两种。</p>
<h4 id="6-2-1-通过kmalloc自行分配"><a href="#6-2-1-通过kmalloc自行分配" class="headerlink" title="6.2.1 通过kmalloc自行分配"></a><font size=3>6.2.1 通过kmalloc自行分配</font></h4><p>第一种分配方法就是<strong>通过kmalloc自行分配</strong>（一般是跟随上层数据结构分配），并在初始化后添加到kernel。</p>
<h5 id="6-2-1-1-kobject-init"><a href="#6-2-1-1-kobject-init" class="headerlink" title="6.2.1.1 kobject_init()"></a><font size=3>6.2.1.1 kobject_init()</font></h5><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L330">kobject_init()</a>函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * kobject_init - initialize a kobject structure</span></span><br><span class="line"><span class="comment"> * @kobj: pointer to the kobject to initialize</span></span><br><span class="line"><span class="comment"> * @ktype: pointer to the ktype for this kobject.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function will properly initialize a kobject such that it can then</span></span><br><span class="line"><span class="comment"> * be passed to the kobject_add() call.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * After this function is called, the kobject MUST be cleaned up by a call</span></span><br><span class="line"><span class="comment"> * to kobject_put(), not by a call to kfree directly to ensure that all of</span></span><br><span class="line"><span class="comment"> * the memory is cleaned up properly.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">kobject_init</span><span class="params">(<span class="keyword">struct</span> kobject *kobj, <span class="keyword">struct</span> kobj_type *ktype)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">char</span> *err_str;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (!kobj) &#123;</span><br><span class="line">		err_str = <span class="string">&quot;invalid kobject pointer!&quot;</span>;</span><br><span class="line">		<span class="keyword">goto</span> error;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (!ktype) &#123;</span><br><span class="line">		err_str = <span class="string">&quot;must have a ktype to be initialized properly!\n&quot;</span>;</span><br><span class="line">		<span class="keyword">goto</span> error;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (kobj-&gt;state_initialized) &#123;</span><br><span class="line">		<span class="comment">/* do not error out as sometimes we can recover */</span></span><br><span class="line">		pr_err(<span class="string">&quot;kobject (%p): tried to init an initialized object, something is seriously wrong.\n&quot;</span>,</span><br><span class="line">		       kobj);</span><br><span class="line">		dump_stack();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	kobject_init_internal(kobj);</span><br><span class="line">	kobj-&gt;ktype = ktype;</span><br><span class="line">	<span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">error:</span><br><span class="line">	pr_err(<span class="string">&quot;kobject (%p): %s\n&quot;</span>, kobj, err_str);</span><br><span class="line">	dump_stack();</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(kobject_init);</span><br></pre></td></tr></table></figure>

<p><code>kobject_init</code>：初始化通过kmalloc等内存分配函数获得的struct kobject指针。主要执行逻辑为：</p>
<p>（1）第17 - 24 行：确认kobj和ktype不为空；</p>
<p>（2）第25行：如果该指针已经初始化过（判断kobj&rarr;state_initialized），打印错误提示及堆栈信息（但不是致命错误，所以还可以继续）；</p>
<p>（3）第32行：初始化kobj内部的参数，包括引用计数kref、list_head、各种标志等;</p>
<p>（4）第33行：将输入形参 ktype 赋予 kobj&rarr;ktype 。</p>
<h5 id="6-2-1-2-kobject-add"><a href="#6-2-1-2-kobject-add" class="headerlink" title="6.2.1.2 kobject_add()"></a><font size=3>6.2.1.2 kobject_add()</font></h5><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L386">kobject_add()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">kobject_add</span><span class="params">(<span class="keyword">struct</span> kobject *kobj, <span class="keyword">struct</span> kobject *parent,</span></span><br><span class="line"><span class="params">		<span class="type">const</span> <span class="type">char</span> *fmt, ...)</span></span><br><span class="line">&#123;</span><br><span class="line">	va_list args;</span><br><span class="line">	<span class="type">int</span> retval;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (!kobj)</span><br><span class="line">		<span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (!kobj-&gt;state_initialized) &#123;</span><br><span class="line">		pr_err(<span class="string">&quot;kobject &#x27;%s&#x27; (%p): tried to add an uninitialized object, something is seriously wrong.\n&quot;</span>,</span><br><span class="line">		       kobject_name(kobj), kobj);</span><br><span class="line">		dump_stack();</span><br><span class="line">		<span class="keyword">return</span> -EINVAL;</span><br><span class="line">	&#125;</span><br><span class="line">	va_start(args, fmt);</span><br><span class="line">	retval = kobject_add_varg(kobj, parent, fmt, args);</span><br><span class="line">	va_end(args);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> retval;</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(kobject_add);</span><br></pre></td></tr></table></figure>

<p>如果koibject需要添加到sysfs中，则必须要调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L386">kobject_add()</a> 函数。它将初始化完成的kobject添加到kernel中，参数包括需要添加的kobject、该kobject的parent（用于形成层次结构，可以为空）、用于提供kobject name的格式化字符串。主要执行逻辑为：</p>
<p>（1）确认kobj不为空，确认kobj已经初始化，否则错误退出。</p>
<p>（2）调用内部接口 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L370">kobject_add_varg()</a>，完成添加操作，具体调用逻辑如下：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105154536844.png" alt="image-20250105154536844" />

<p>在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L66">populate_dir()</a> 函数中逐个处理内核对象所属对象类型的默认属性，对每个属性，调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/sysfs.h#L510">sysfs_create_file()</a> 函数在内核对象的目录下创建以属性名为名字的文件。<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L386">kobject_add()</a> 中只会为默认属性自动创建文件。</p>
<h5 id="6-2-1-3-kobject-init-and-add"><a href="#6-2-1-3-kobject-init-and-add" class="headerlink" title="6.2.1.3 kobject_init_and_add()"></a><font size=3>6.2.1.3 kobject_init_and_add()</font></h5><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L434">kobject_init_and_add()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">kobject_init_and_add</span><span class="params">(<span class="keyword">struct</span> kobject *kobj, <span class="keyword">struct</span> kobj_type *ktype,</span></span><br><span class="line"><span class="params">			 <span class="keyword">struct</span> kobject *parent, <span class="type">const</span> <span class="type">char</span> *fmt, ...)</span></span><br><span class="line">&#123;</span><br><span class="line">	va_list args;</span><br><span class="line">	<span class="type">int</span> retval;</span><br><span class="line"></span><br><span class="line">	kobject_init(kobj, ktype);</span><br><span class="line"></span><br><span class="line">	va_start(args, fmt);</span><br><span class="line">	retval = kobject_add_varg(kobj, parent, fmt, args);</span><br><span class="line">	va_end(args);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> retval;</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL_GPL(kobject_init_and_add);</span><br></pre></td></tr></table></figure>

<p>qis其实就是上面两个接口的一个组合。<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L370">kobject_add_varg()</a>解析格式化字符串，将结果赋予kobj&rarr;name，之后调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L217">kobject_add_internal()</a> 接口，完成真正的添加操作。 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L217">kobject_add_internal()</a> 将kobject添加到kernel，主要执行的逻辑为：</p>
<p>（1）校验kobj以及kobj&rarr;name的合法性，若不合法打印错误信息并退出；</p>
<p>（2）调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L603">kobject_get()</a> 增加该kobject的parent的引用计数（如果存在parent的话）；</p>
<p>（3）如果存在kset，则调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L181">kobj_kset_join()</a>接口将本kobject加入到此kset的kobject链表中。同时，如果该kobject没有parent，却存在kset，则将它的parent设为kset（kset是一个特殊的kobject），并增加kset的引用计数；</p>
<p>（4）通过 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L83">create_dir()</a> 接口，调用sysfs的相关接口，在sysfs下创建该kobject对应的目录；</p>
<p>（5）如果创建失败，则执行后续的回滚操作，否则将 kobj&rarr;state_in_sysfs置为1；</p>
<p>这种方式分配的kobject，会在引用计数变为0时，由kobject_put调用其 kobj_type 的release接口，释放内存空间，具体可参考后面有关kobject_put的笔记。</p>
<h4 id="6-2-2-使用kobject-create-创建"><a href="#6-2-2-使用kobject-create-创建" class="headerlink" title="6.2.2 使用kobject_create()创建"></a><font size=3>6.2.2 使用kobject_create()创建</font></h4><p>kobject模块可以使用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L725">kobject_create()</a> 自行分配空间，并内置了一个ktype（dynamic_kobj_ktype），用于在计数为0时释放空间。</p>
<h5 id="6-2-2-1-kobject-create"><a href="#6-2-2-1-kobject-create" class="headerlink" title="6.2.2.1 kobject_create()"></a><font size=3>6.2.2.1 kobject_create()</font></h5><p> <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L725">kobject_create()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> kobject *<span class="title function_">kobject_create</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">kobj</span>;</span></span><br><span class="line"></span><br><span class="line">	kobj = kzalloc(<span class="keyword">sizeof</span>(*kobj), GFP_KERNEL);</span><br><span class="line">	<span class="keyword">if</span> (!kobj)</span><br><span class="line">		<span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">	kobject_init(kobj, &amp;dynamic_kobj_ktype);</span><br><span class="line">	<span class="keyword">return</span> kobj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>该接口为kobj分配内存空间，并以<code>dynamic_kobj_ktype</code>为参数，调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L330">kobject_init()</a> 接口，完成后续的初始化操作。</p>
<h5 id="6-2-2-2-kobject-add"><a href="#6-2-2-2-kobject-add" class="headerlink" title="6.2.2.2 kobject_add()"></a><font size=3>6.2.2.2 kobject_add()</font></h5><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L386">kobject_add()</a> 函数在前面已经了解过了。</p>
<h5 id="6-2-2-3-kobject-create-and-add"><a href="#6-2-2-3-kobject-create-and-add" class="headerlink" title="6.2.2.3 kobject_create_and_add()"></a><font size=3>6.2.2.3 kobject_create_and_add()</font></h5><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L748">kobject_create_and_add()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> kobject *<span class="title function_">kobject_create_and_add</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *name, <span class="keyword">struct</span> kobject *parent)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">kobj</span>;</span></span><br><span class="line">	<span class="type">int</span> retval;</span><br><span class="line"></span><br><span class="line">	kobj = kobject_create();</span><br><span class="line">	<span class="keyword">if</span> (!kobj)</span><br><span class="line">		<span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">	retval = kobject_add(kobj, parent, <span class="string">&quot;%s&quot;</span>, name);</span><br><span class="line">	<span class="keyword">if</span> (retval) &#123;</span><br><span class="line">		pr_warn(<span class="string">&quot;%s: kobject_add error: %d\n&quot;</span>, __func__, retval);</span><br><span class="line">		kobject_put(kobj);</span><br><span class="line">		kobj = <span class="literal">NULL</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> kobj;</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL_GPL(kobject_create_and_add);</span><br></pre></td></tr></table></figure>

<p>其实就是  <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L725">kobject_create()</a> 和<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L386">kobject_add()</a> 的组合。</p>
<h3 id="6-3-kobject引用计数的加减"><a href="#6-3-kobject引用计数的加减" class="headerlink" title="6.3 kobject引用计数的加减"></a><font size=3>6.3 kobject引用计数的加减</font></h3><blockquote>
<p>引用计数是啥？后面会了解到的，这里主要是看一下object常用的api。</p>
</blockquote>
<p>通过 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L603">kobject_get()</a> 和 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L696">kobject_put()</a> 可以修改kobject的引用计数kref，并在kref为0时，调用对应ktype的release接口，释放占用空间。</p>
<h4 id="6-3-1-kobject-get"><a href="#6-3-1-kobject-get" class="headerlink" title="6.3.1 kobject_get()"></a><font size=3>6.3.1 kobject_get()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L603">kobject_get()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * kobject_get - increment refcount for object.</span></span><br><span class="line"><span class="comment"> * @kobj: object.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">struct</span> kobject *<span class="title function_">kobject_get</span><span class="params">(<span class="keyword">struct</span> kobject *kobj)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (kobj) &#123;</span><br><span class="line">		<span class="keyword">if</span> (!kobj-&gt;state_initialized)</span><br><span class="line">			WARN(<span class="number">1</span>, KERN_WARNING</span><br><span class="line">				<span class="string">&quot;kobject: &#x27;%s&#x27; (%p): is not initialized, yet kobject_get() is being called.\n&quot;</span>,</span><br><span class="line">			     kobject_name(kobj), kobj);</span><br><span class="line">		kref_get(&amp;kobj-&gt;kref);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> kobj;</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(kobject_get);</span><br></pre></td></tr></table></figure>

<h4 id="6-3-2-kobject-put"><a href="#6-3-2-kobject-put" class="headerlink" title="6.3.2 kobject_put()"></a><font size=3>6.3.2 kobject_put()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L696">kobject_put()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * kobject_put - decrement refcount for object.</span></span><br><span class="line"><span class="comment"> * @kobj: object.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Decrement the refcount, and if 0, call kobject_cleanup().</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">kobject_put</span><span class="params">(<span class="keyword">struct</span> kobject *kobj)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (kobj) &#123;</span><br><span class="line">		<span class="keyword">if</span> (!kobj-&gt;state_initialized)</span><br><span class="line">			WARN(<span class="number">1</span>, KERN_WARNING</span><br><span class="line">				<span class="string">&quot;kobject: &#x27;%s&#x27; (%p): is not initialized, yet kobject_put() is being called.\n&quot;</span>,</span><br><span class="line">			     kobject_name(kobj), kobj);</span><br><span class="line">		kref_put(&amp;kobj-&gt;kref, kobject_release);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(kobject_put);</span><br></pre></td></tr></table></figure>

<p>以内部接口 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L680">kobject_release()</a> 为参数，调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kref.h#L67">kref_put()</a> 。kref模块会在引用计数为零时，调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L680">kobject_release()</a> 。</p>
<h4 id="6-3-3-kobject-release"><a href="#6-3-3-kobject-release" class="headerlink" title="6.3.3 kobject_release()"></a><font size=3>6.3.3 kobject_release()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L680">kobject_release()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">kobject_release</span><span class="params">(<span class="keyword">struct</span> kref *kref)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">kobj</span> =</span> container_of(kref, <span class="keyword">struct</span> kobject, kref);</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> CONFIG_DEBUG_KOBJECT_RELEASE</span></span><br><span class="line">	<span class="type">unsigned</span> <span class="type">long</span> delay = HZ + HZ * (get_random_int() &amp; <span class="number">0x3</span>);</span><br><span class="line">	pr_info(<span class="string">&quot;kobject: &#x27;%s&#x27; (%p): %s, parent %p (delayed %ld)\n&quot;</span>,</span><br><span class="line">		 kobject_name(kobj), kobj, __func__, kobj-&gt;parent, delay);</span><br><span class="line">	INIT_DELAYED_WORK(&amp;kobj-&gt;release, kobject_delayed_cleanup);</span><br><span class="line"></span><br><span class="line">	schedule_delayed_work(&amp;kobj-&gt;release, delay);</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">	kobject_cleanup(kobj);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L680">kobject_release()</a> 函数通过kref结构，获取kobject指针，并调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L633">kobject_cleanup()</a> 函数：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * kobject_cleanup - free kobject resources.</span></span><br><span class="line"><span class="comment"> * @kobj: object to cleanup</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">kobject_cleanup</span><span class="params">(<span class="keyword">struct</span> kobject *kobj)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kobj_type</span> *<span class="title">t</span> =</span> get_ktype(kobj);</span><br><span class="line">	<span class="type">const</span> <span class="type">char</span> *name = kobj-&gt;name;</span><br><span class="line"></span><br><span class="line">	pr_debug(<span class="string">&quot;kobject: &#x27;%s&#x27; (%p): %s, parent %p\n&quot;</span>,</span><br><span class="line">		 kobject_name(kobj), kobj, __func__, kobj-&gt;parent);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (t &amp;&amp; !t-&gt;release)</span><br><span class="line">		pr_debug(<span class="string">&quot;kobject: &#x27;%s&#x27; (%p): does not have a release() function, it is broken and must be fixed.\n&quot;</span>,</span><br><span class="line">			 kobject_name(kobj), kobj);</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* send &quot;remove&quot; if the caller did not do it but sent &quot;add&quot; */</span></span><br><span class="line">	<span class="keyword">if</span> (kobj-&gt;state_add_uevent_sent &amp;&amp; !kobj-&gt;state_remove_uevent_sent) &#123;</span><br><span class="line">		pr_debug(<span class="string">&quot;kobject: &#x27;%s&#x27; (%p): auto cleanup &#x27;remove&#x27; event\n&quot;</span>,</span><br><span class="line">			 kobject_name(kobj), kobj);</span><br><span class="line">		kobject_uevent(kobj, KOBJ_REMOVE);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* remove from sysfs if the caller did not do it */</span></span><br><span class="line">	<span class="keyword">if</span> (kobj-&gt;state_in_sysfs) &#123;</span><br><span class="line">		pr_debug(<span class="string">&quot;kobject: &#x27;%s&#x27; (%p): auto cleanup kobject_del\n&quot;</span>,</span><br><span class="line">			 kobject_name(kobj), kobj);</span><br><span class="line">		kobject_del(kobj);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (t &amp;&amp; t-&gt;release) &#123;</span><br><span class="line">		pr_debug(<span class="string">&quot;kobject: &#x27;%s&#x27; (%p): calling ktype release\n&quot;</span>,</span><br><span class="line">			 kobject_name(kobj), kobj);</span><br><span class="line">		t-&gt;release(kobj);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">/* free name if we allocated it */</span></span><br><span class="line">	<span class="keyword">if</span> (name) &#123;</span><br><span class="line">		pr_debug(<span class="string">&quot;kobject: &#x27;%s&#x27;: free name\n&quot;</span>, name);</span><br><span class="line">		kfree_const(name);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L633">kobject_cleanup()</a> 负责释放kobject占用的空间，主要执行逻辑如下：</p>
<p>（1）检查该kobject是否有ktype，如果没有，打印警告信息；</p>
<p>（2）如果该kobject向用户空间发送了ADD uevent但没有发送REMOVE uevent，补发REMOVE uevent；</p>
<p>（3）如果该kobject有在sysfs文件系统注册，调用kobject_del接口，删除它在sysfs中的注册；</p>
<p>（4）调用该kobject的ktype的release接口，释放内存空间；</p>
<p>（5）释放该kobject的name所占用的内存空间；</p>
<h2 id="7-创建kobject-demo"><a href="#7-创建kobject-demo" class="headerlink" title="7. 创建kobject demo"></a><font size=3>7. 创建kobject demo</font></h2><h3 id="7-1-demo源码"><a href="#7-1-demo源码" class="headerlink" title="7.1 demo源码"></a><font size=3>7.1 demo源码</font></h3><p>可以直接看这里：<a target="_blank" rel="noopener" href="https://gitee.com/sumumm/imx6ull-driver-demo/tree/master/05_device_model/02_kobject_create">05_device_model&#x2F;02_kobject_create · 苏木&#x2F;imx6ull-driver-demo - 码云 - 开源中国</a></p>
<details class="folding-tag" blue><summary> 点击查看详情 </summary>
              <div class='content'>
              <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/init.h&gt;</span> <span class="comment">/* module_init module_exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span> <span class="comment">/* MODULE_LICENSE */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kobject.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./timestamp_autogenerated.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./version_autogenerated.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./sdrv_common.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// #undef PRT</span></span><br><span class="line"><span class="comment">// #undef PRTE</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> PRT</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PRT printk</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> PRTE</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PRTE printk</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义三个kobject指针变量：skobject1、skobject2、skobject3</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject1</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject2</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject3</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobj_type</span> <span class="title">stype</span> =</span> &#123;<span class="number">0</span>&#125;; <span class="comment">// 定义一个kobj_type结构体变量stype，用于描述kobject的类型。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  sdriver_demo_init()</span></span><br><span class="line"><span class="comment"> * @note   </span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> __init <span class="type">int</span> <span class="title function_">sdriver_demo_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	printk(<span class="string">&quot;*** [%s:%d]Build Time: %s %s, git version:%s ***\n&quot;</span>, __FUNCTION__,</span><br><span class="line">           __LINE__, KERNEL_KO_DATE, KERNEL_KO_TIME, KERNEL_KO_VERSION);</span><br><span class="line">    PRT(<span class="string">&quot;sdriver_demo module init!\n&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 创建kobject的第一种方法</span></span><br><span class="line">    <span class="comment">// 创建并添加一个名为&quot;skobject1&quot;的kobject对象，父kobject为NULL</span></span><br><span class="line">    skobject1 = kobject_create_and_add(<span class="string">&quot;skobject1&quot;</span>, <span class="literal">NULL</span>);</span><br><span class="line">    <span class="comment">// 创建并添加一个名为&quot;skobject2&quot;的kobject对象，父kobject为skobject1。</span></span><br><span class="line">    skobject2 = kobject_create_and_add(<span class="string">&quot;skobject2&quot;</span>, skobject1);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 创建kobject的第二种方法</span></span><br><span class="line">    <span class="comment">// 1.使用kzalloc函数分配了一个kobject对象的内存</span></span><br><span class="line">    skobject3 = kzalloc(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> kobject), GFP_KERNEL);</span><br><span class="line">    <span class="comment">// 2.初始化并添加到内核中，名为&quot;skobject3&quot;。</span></span><br><span class="line">    ret = kobject_init_and_add(skobject3, &amp;stype, <span class="literal">NULL</span>, <span class="string">&quot;%s&quot;</span>, <span class="string">&quot;skobject3&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        PRTE(<span class="string">&quot;kobject_init_and_add fail!ret=%d\n&quot;</span>, ret);</span><br><span class="line">        <span class="keyword">goto</span> err_kobject_init_and_add;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err_kobject_init_and_add:</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  sdriver_demo_exit()</span></span><br><span class="line"><span class="comment"> * @note   </span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> __exit <span class="type">void</span> <span class="title function_">sdriver_demo_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">// 释放之前创建的kobject对象</span></span><br><span class="line">    kobject_put(skobject1);</span><br><span class="line">    kobject_put(skobject2);</span><br><span class="line">    kobject_put(skobject3);</span><br><span class="line">    PRT(<span class="string">&quot;sdriver_demo module exit!\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">module_init(sdriver_demo_init); <span class="comment">// 将__init定义的函数指定为驱动的入口函数</span></span><br><span class="line">module_exit(sdriver_demo_exit); <span class="comment">// 将__exit定义的函数指定为驱动的出口函数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 模块信息(通过 modinfo chrdev_led_demo 查看) */</span></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL v2&quot;</span>);            <span class="comment">/* 源码的许可证协议 */</span></span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;sumu&quot;</span>);               <span class="comment">/* 字符串常量内容为模块作者说明 */</span></span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;Description&quot;</span>);   <span class="comment">/* 字符串常量内容为模块功能说明 */</span></span><br><span class="line">MODULE_ALIAS(<span class="string">&quot;module&#x27;s other name&quot;</span>); <span class="comment">/* 字符串常量内容为模块别名 */</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p>我们执行make编译，最后就会得到sdriver_demo.ko文件。</p>
<h3 id="7-2-开发板验证"><a href="#7-2-开发板验证" class="headerlink" title="7.2 开发板验证"></a><font size=3>7.2 开发板验证</font></h3><p>我们拷贝到开发板，然后加载驱动：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105161224342.png" alt="image-20250105161224342" />

<p>然后我们就可以在&#x2F;sys目录下看到我们创建的 skobject1 和 skobject3，skobject2 位于 &#x2F;sys&#x2F;skobject1 目录下。卸载驱动模块的时候这几个目录都会被删除。</p>
<h1 id="三、kset"><a href="#三、kset" class="headerlink" title="三、kset"></a><font size=3>三、kset</font></h1><h2 id="1-kset是什么？"><a href="#1-kset是什么？" class="headerlink" title="1. kset是什么？"></a><font size=3>1. kset是什么？</font></h2><p>kset（内核对象集合）是一种用于组织和管理一组相关 kobject 的容器（或者说叫集合）。 kset 是 kobject 的一种扩展， 它提供了一种层次化的组织结构， 可以将一组相关的 kobject 组织在一起。   </p>
<blockquote>
<p>kset是一个特殊的kobject（它也会在”&#x2F;sys&#x2F;“文件系统中以目录的形式出现），它用来集合相似的kobject（这些kobject可以是相同属性的，也可以不同属性的）。</p>
</blockquote>
<p>kset定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kobject.h#L176">kobject.h - include&#x2F;linux&#x2F;kobject.h - <em>struct kset</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">**</span><br><span class="line"> * <span class="class"><span class="keyword">struct</span> <span class="title">kset</span> - <span class="title">a</span> <span class="title">set</span> <span class="title">of</span> <span class="title">kobjects</span> <span class="title">of</span> <span class="title">a</span> <span class="title">specific</span> <span class="title">type</span>, <span class="title">belonging</span> <span class="title">to</span> <span class="title">a</span> <span class="title">specific</span> <span class="title">subsystem</span>.</span></span><br><span class="line"><span class="class"> *</span></span><br><span class="line"><span class="class"> * <span class="title">A</span> <span class="title">kset</span> <span class="title">defines</span> <span class="title">a</span> <span class="title">group</span> <span class="title">of</span> <span class="title">kobjects</span>.  <span class="title">They</span> <span class="title">can</span> <span class="title">be</span> <span class="title">individually</span></span></span><br><span class="line"><span class="class"> * <span class="title">different</span> &quot;<span class="title">types</span>&quot; <span class="title">but</span> <span class="title">overall</span> <span class="title">these</span> <span class="title">kobjects</span> <span class="title">all</span> <span class="title">want</span> <span class="title">to</span> <span class="title">be</span> <span class="title">grouped</span></span></span><br><span class="line"><span class="class"> * <span class="title">together</span> <span class="title">and</span> <span class="title">operated</span> <span class="title">on</span> <span class="title">in</span> <span class="title">the</span> <span class="title">same</span> <span class="title">manner</span>.  <span class="title">ksets</span> <span class="title">are</span> <span class="title">used</span> <span class="title">to</span></span></span><br><span class="line"><span class="class"> * <span class="title">define</span> <span class="title">the</span> <span class="title">attribute</span> <span class="title">callbacks</span> <span class="title">and</span> <span class="title">other</span> <span class="title">common</span> <span class="title">events</span> <span class="title">that</span> <span class="title">happen</span> <span class="title">to</span></span></span><br><span class="line"><span class="class"> * <span class="title">a</span> <span class="title">kobject</span>.</span></span><br><span class="line"><span class="class"> *</span></span><br><span class="line"><span class="class"> * @<span class="title">list</span>:</span> the <span class="built_in">list</span> of all kobjects <span class="keyword">for</span> this kset</span><br><span class="line"> * @list_lock: a lock <span class="keyword">for</span> iterating over the kobjects</span><br><span class="line"> * @kobj: the embedded kobject <span class="keyword">for</span> this <span class="title function_">kset</span> <span class="params">(recursion, isn<span class="string">&#x27;t it fun...)</span></span></span><br><span class="line"><span class="string"><span class="params"> * @uevent_ops: the set of uevent operations for this kset.  These are</span></span></span><br><span class="line"><span class="string"><span class="params"> * called whenever a kobject has something happen to it so that the kset</span></span></span><br><span class="line"><span class="string"><span class="params"> * can add new environment variables, or filter out the uevents if so</span></span></span><br><span class="line"><span class="string"><span class="params"> * desired.</span></span></span><br><span class="line"><span class="string"><span class="params"> */</span></span></span><br><span class="line"><span class="string"><span class="params">struct kset &#123;</span></span></span><br><span class="line"><span class="string"><span class="params">	struct list_head list;</span></span></span><br><span class="line"><span class="string"><span class="params">	spinlock_t list_lock;</span></span></span><br><span class="line"><span class="string"><span class="params">	struct kobject kobj;</span></span></span><br><span class="line"><span class="string"><span class="params">	const struct kset_uevent_ops *uevent_ops;</span></span></span><br><span class="line"><span class="string"><span class="params">&#125; __randomize_layout;</span></span></span><br></pre></td></tr></table></figure>

<ul>
<li>list：指向该kset下所有的kobject的链表。用于将 kset 链接到全局 kset 链表中， 以便对 kset 进行遍历和管理。  </li>
<li>list_lock：避免操作链表时产生竞态的自旋锁，确保线程安全性。  </li>
<li>kobj：该kset自己的kobject（kset是一个特殊的kobject，也会在sysfs中以目录的形式体现）。 用于在&#x2F;sys 目录下创建对应的目录， 并与kset 关联。  </li>
<li>uevent_ops：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kobject.h#L156">struct kset_uevent_ops</a> 类型，该kset的uevent操作函数集，当kset中的某些kobject对象状态发生变化需要通知用户空间时，调用其中对应的函数来完成。当任何kobject需要上报uevent时，都要调用它所从属的kset的uevent_ops，添加环境变量，或者过滤event（kset可以决定哪些event可以上报）。因此，如果一个kobject不属于任何kset时，是不允许发送uevent的。</li>
</ul>
<p>kset 通过包含一个 kobject 作为其成员， 将 kset 本身表示为一个 kobject， 并使用 kobj 来管理和操作 kset。 通过 list 字段， kset 可以<br>链接到全局 kset 链表中， 以便进行全局的遍历和管理。 同时， list_lock 字段用于保护对 kset 链表的并发访问。 kset 还可以定义自己的 uevent 操作， 用于处理与 kset 相关的 uevent 事件， 例如在添加或删除 kobject 时发送相应的 uevent 通知。  </p>
<p>这些字段共同构成了 kset 的基本属性和关系， 用于在内核中组织和管理一组相关的kobject。 kset 提供了一种层次化的组织结构， 并与 sysfs 目录相对应， 方便对 kobject 进行管理和操作。  </p>
<h2 id="2-kset和kobject的关系"><a href="#2-kset和kobject的关系" class="headerlink" title="2. kset和kobject的关系"></a><font size=3>2. kset和kobject的关系</font></h2><p>在 Linux 内核中， kset 和 kobject 是相关联的两个概念， 它们之间存在一种层次化的关系，  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105153000146.png" alt="image-20250105153000146" />

<p>（1）kset 是 kobject 的一种扩展： kset 可以被看作是 kobject 的一种特殊形式， 它扩展了 kobject并提供了一些额外的功能。 kset 可以包含多个 kobject， 形成一个层次化的组织结构。  </p>
<p>（2）kobject 属于一个 kset： 每个 kobject 都属于一个 kset。kobject 结构体中的 struct kset *kset字段指向所属的 kset。 这个关联关系表示了 kobject 所在的集合或组织。  多个kset的时候如下图：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105153345305.png" alt="image-20250105153345305" />

<p>通过 kset 和 kobject 之间的关系， 可以实现对内核对象的层次化管理和操作。 kset 提供了对 kobject 的集合管理接口， 可以通过 kset 来迭代、 查找、 添加或删除 kobject。 同时， kset 也提供了特定于集合的功能， 例如在集合级别处理 uevent 事件。</p>
<p>总结起来， kset 和 kobject 之间的关系是： 一个 kset 可以包含多个 kobject， 而一个 kobject只能属于一个 kset。 kset 提供了对kobject  的集合管理和操作接口， 用于组织和管理具有相似特性或关系的 kobject。 这种关系使得内核能够以一种统一的方式管理和操作不同类型的内核对象。  </p>
<h2 id="3-相关API"><a href="#3-相关API" class="headerlink" title="3. 相关API"></a><font size=3>3. 相关API</font></h2><h3 id="3-4-kset的初始化、注册"><a href="#3-4-kset的初始化、注册" class="headerlink" title="3.4 kset的初始化、注册"></a><font size=3>3.4 kset的初始化、注册</font></h3><p>Kset是一个特殊的kobject，因此其初始化、注册等操作也会调用kobject的相关接口，除此之外，会有它特有的部分。另外，和kobject一样，kset的内存分配，可以由上层软件通过kmalloc自行分配，也可以由kobject模块负责分配。</p>
<h4 id="3-4-1-kset-init"><a href="#3-4-1-kset-init" class="headerlink" title="3.4.1 kset_init()"></a><font size=3>3.4.1 kset_init()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L783">kset_init()</a> 函数定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * kset_init - initialize a kset for use</span></span><br><span class="line"><span class="comment"> * @k: kset</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">kset_init</span><span class="params">(<span class="keyword">struct</span> kset *k)</span></span><br><span class="line">&#123;</span><br><span class="line">	kobject_init_internal(&amp;k-&gt;kobj);</span><br><span class="line">	INIT_LIST_HEAD(&amp;k-&gt;<span class="built_in">list</span>);</span><br><span class="line">	spin_lock_init(&amp;k-&gt;list_lock);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>该接口用于初始化已分配的kset，主要包括调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L204">kobject_init_internal()</a> 初始化其kobject，然后初始化kset的链表。需要注意的时，如果使用此接口，上层软件必须提供该kset中的kobject的ktype。</p>
<h4 id="3-4-2-kset-register"><a href="#3-4-2-kset-register" class="headerlink" title="3.4.2 kset_register()"></a><font size=3>3.4.2 kset_register()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L822">kset_register()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * kset_register - initialize and add a kset.</span></span><br><span class="line"><span class="comment"> * @k: kset.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">kset_register</span><span class="params">(<span class="keyword">struct</span> kset *k)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (!k)</span><br><span class="line">		<span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">	kset_init(k);</span><br><span class="line">	err = kobject_add_internal(&amp;k-&gt;kobj);</span><br><span class="line">	<span class="keyword">if</span> (err)</span><br><span class="line">		<span class="keyword">return</span> err;</span><br><span class="line">	kobject_uevent(&amp;k-&gt;kobj, KOBJ_ADD);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(kset_register);</span><br></pre></td></tr></table></figure>

<p>先调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L780">kset_init()</a>，然后调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L217">kobject_add_internal()</a> 将其kobject添加到kernel。</p>
<h4 id="3-4-3-kset-unregister"><a href="#3-4-3-kset-unregister" class="headerlink" title="3.4.3 kset_unregister()"></a><font size=3>3.4.3 kset_unregister()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L842">kset_unregister()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * kset_unregister - remove a kset.</span></span><br><span class="line"><span class="comment"> * @k: kset.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">kset_unregister</span><span class="params">(<span class="keyword">struct</span> kset *k)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (!k)</span><br><span class="line">		<span class="keyword">return</span>;</span><br><span class="line">	kobject_del(&amp;k-&gt;kobj);</span><br><span class="line">	kobject_put(&amp;k-&gt;kobj);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(kset_unregister);</span><br></pre></td></tr></table></figure>

<p>直接调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L696">kobject_put()</a> 释放其kobject。当其kobject的引用计数为0时，即调用ktype的release接口释放kset占用的空间。</p>
<h4 id="3-4-4-kset-create-and-add"><a href="#3-4-4-kset-create-and-add" class="headerlink" title="3.4.4 kset_create_and_add()"></a><font size=3>3.4.4 kset_create_and_add()</font></h4><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L947">kset_create_and_add()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> kset *<span class="title function_">kset_create_and_add</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *name,</span></span><br><span class="line"><span class="params">				 <span class="type">const</span> <span class="keyword">struct</span> kset_uevent_ops *uevent_ops,</span></span><br><span class="line"><span class="params">				 <span class="keyword">struct</span> kobject *parent_kobj)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">kset</span> *<span class="title">kset</span>;</span></span><br><span class="line">	<span class="type">int</span> error;</span><br><span class="line"></span><br><span class="line">	kset = kset_create(name, uevent_ops, parent_kobj);</span><br><span class="line">	<span class="keyword">if</span> (!kset)</span><br><span class="line">		<span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">	error = kset_register(kset);</span><br><span class="line">	<span class="keyword">if</span> (error) &#123;</span><br><span class="line">		kfree(kset);</span><br><span class="line">		<span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> kset;</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL_GPL(kset_create_and_add);</span><br></pre></td></tr></table></figure>

<p>会调用内部接口 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L917">kset_create()</a> 动态创建一个kset，并调用 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L825">kset_register()</a> 将其注册到kernel。内部接口 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L917">kset_create()</a> 使用kzalloc分配一个kset空间，并定义一个kset_ktype类型的ktype，用于释放所有由它分配的kset空间。</p>
<h2 id="4-创建kset-demo"><a href="#4-创建kset-demo" class="headerlink" title="4. 创建kset demo"></a><font size=3>4. 创建kset demo</font></h2><h3 id="4-1-demo源码"><a href="#4-1-demo源码" class="headerlink" title="4.1 demo源码"></a><font size=3>4.1 demo源码</font></h3><p>可以直接看这里：<a target="_blank" rel="noopener" href="https://gitee.com/sumumm/imx6ull-driver-demo/tree/master/05_device_model/03_kset_create">05_device_model&#x2F;03_kset_create · 苏木&#x2F;imx6ull-driver-demo - 码云 - 开源中国</a></p>
<details class="folding-tag" blue><summary> 点击查看详情 </summary>
              <div class='content'>
              <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/init.h&gt;</span> <span class="comment">/* module_init module_exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span> <span class="comment">/* MODULE_LICENSE */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kobject.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./timestamp_autogenerated.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./version_autogenerated.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./sdrv_common.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// #undef PRT</span></span><br><span class="line"><span class="comment">// #undef PRTE</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> PRT</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PRT printk</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> PRTE</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PRTE printk</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject1</span> =</span> <span class="literal">NULL</span>; <span class="comment">// 定义kobject结构体指针，用于表示第一个自定义内核对象</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject2</span> =</span> <span class="literal">NULL</span>; <span class="comment">// 定义kobject结构体指针，用于表示第二个自定义内核对象</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobj_type</span> <span class="title">stype</span> =</span> &#123;<span class="number">0</span>&#125;;     <span class="comment">// 定义一个kobj_type结构体变量stype，用于描述kobject的类型。</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kset</span> *<span class="title">skset</span> =</span> <span class="literal">NULL</span>;        <span class="comment">// 定义kset结构体指针，用于表示自定义内核对象的集合</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  sdriver_demo_init()</span></span><br><span class="line"><span class="comment"> * @note   </span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> __init <span class="type">int</span> <span class="title function_">sdriver_demo_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	printk(<span class="string">&quot;*** [%s:%d]Build Time: %s %s, git version:%s ***\n&quot;</span>, __FUNCTION__,</span><br><span class="line">           __LINE__, KERNEL_KO_DATE, KERNEL_KO_TIME, KERNEL_KO_VERSION);</span><br><span class="line">    PRT(<span class="string">&quot;sdriver_demo module init!\n&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 创建并添加kset，名称为&quot;skset&quot;，父kobject为NULL，属性为NULL</span></span><br><span class="line">    skset = kset_create_and_add(<span class="string">&quot;skset&quot;</span>, <span class="literal">NULL</span>, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 为skobject1分配内存空间，大小为struct kobject的大小，标志为GFP_KERNEL</span></span><br><span class="line">    skobject1 = kzalloc(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> kobject), GFP_KERNEL);</span><br><span class="line">    <span class="comment">// 将skset设置为skobject1的kset属性</span></span><br><span class="line">    skobject1-&gt;kset = skset;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 初始化并添加skobject1，类型为mytype，父kobject为NULL，格式化字符串为&quot;skobject1&quot;</span></span><br><span class="line">    ret = kobject_init_and_add(skobject1, &amp;stype, <span class="literal">NULL</span>, <span class="string">&quot;%s&quot;</span>, <span class="string">&quot;skobject1&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        PRTE(<span class="string">&quot;kobject_init_and_add fail!ret=%d\n&quot;</span>, ret);</span><br><span class="line">        <span class="keyword">goto</span> err_kobject_init_and_add_1;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 为skobject2分配内存空间，大小为struct kobject的大小，标志为GFP_KERNEL</span></span><br><span class="line">    skobject2 = kzalloc(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> kobject), GFP_KERNEL);</span><br><span class="line">    <span class="comment">// 将skset设置为skobject2的kset属性</span></span><br><span class="line">    skobject2-&gt;kset = skset;</span><br><span class="line">    <span class="comment">// 初始化并添加skobject2，类型为stype，父kobject为NULL，格式化字符串为&quot;skobject2&quot;</span></span><br><span class="line">    ret = kobject_init_and_add(skobject2, &amp;stype, <span class="literal">NULL</span>, <span class="string">&quot;%s&quot;</span>, <span class="string">&quot;skobject2&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        PRTE(<span class="string">&quot;kobject_init_and_add fail!ret=%d\n&quot;</span>, ret);</span><br><span class="line">        <span class="keyword">goto</span> err_kobject_init_and_add_2;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err_kobject_init_and_add_1:</span><br><span class="line">err_kobject_init_and_add_2:</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  sdriver_demo_exit()</span></span><br><span class="line"><span class="comment"> * @note   </span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> __exit <span class="type">void</span> <span class="title function_">sdriver_demo_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">	</span><br><span class="line">    <span class="comment">// 释放skobject1的引用计数</span></span><br><span class="line">    kobject_put(skobject1);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 释放skobject2的引用计数</span></span><br><span class="line">    kobject_put(skobject2);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// remove a kset</span></span><br><span class="line">    kset_unregister(skset);</span><br><span class="line">    PRT(<span class="string">&quot;sdriver_demo module exit!\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">module_init(sdriver_demo_init); <span class="comment">// 将__init定义的函数指定为驱动的入口函数</span></span><br><span class="line">module_exit(sdriver_demo_exit); <span class="comment">// 将__exit定义的函数指定为驱动的出口函数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 模块信息(通过 modinfo chrdev_led_demo 查看) */</span></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL v2&quot;</span>);            <span class="comment">/* 源码的许可证协议 */</span></span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;sumu&quot;</span>);               <span class="comment">/* 字符串常量内容为模块作者说明 */</span></span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;Description&quot;</span>);   <span class="comment">/* 字符串常量内容为模块功能说明 */</span></span><br><span class="line">MODULE_ALIAS(<span class="string">&quot;module&#x27;s other name&quot;</span>); <span class="comment">/* 字符串常量内容为模块别名 */</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p>然后执行make，编译出sdriver_demo.ko。</p>
<h3 id="4-2-开发板验证"><a href="#4-2-开发板验证" class="headerlink" title="4.2 开发板验证"></a><font size=3>4.2 开发板验证</font></h3><p>我们拷贝到开发板，然后加载驱动：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105164847750.png" alt="image-20250105164847750" />

<p>驱动加载之后，我们进入&#x2F;sys&#x2F;目录下，可以看到创建生成的 kset，如下图所示，我们进到 skset 目录下，可以看到创建的 2 个 kobject。</p>
<h1 id="四、引用计数器"><a href="#四、引用计数器" class="headerlink" title="四、引用计数器"></a><font size=3>四、引用计数器</font></h1><h2 id="1-什么是引用计数器？"><a href="#1-什么是引用计数器？" class="headerlink" title="1. 什么是引用计数器？"></a><font size=3>1. 什么是引用计数器？</font></h2><p>引用计数器（reference counting） 是一种内存管理技术， 用于跟踪对象或资源的引用数量。它通过在对象被引用时增加计数值， 并在引用被释放时减少计数值， 以确定何时可以安全地释放对象或资源。  </p>
<h2 id="2-kref-简介"><a href="#2-kref-简介" class="headerlink" title="2. kref 简介"></a><font size=3>2. kref 简介</font></h2><p>kref 是 Linux 内核中提供的一种引用计数器实现， 它是一种轻量级的引用计数技术， 用于管理内核中的对象的引用计数。在 Linux 系统中， 引用计数器用结构体 kref 来表示。struct kref 定义在<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kref.h#L21">kref.h - include&#x2F;linux&#x2F;kref.h - <em>struct kref</em></a>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kref</span> &#123;</span></span><br><span class="line">	<span class="type">refcount_t</span> refcount;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// include/linux/refcount.h</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">refcount_struct</span> &#123;</span></span><br><span class="line">	<span class="type">atomic_t</span> refs;</span><br><span class="line">&#125; <span class="type">refcount_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// include/linux/types.h</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">	<span class="type">int</span> counter;</span><br><span class="line">&#125; <span class="type">atomic_t</span>;</span><br></pre></td></tr></table></figure>

<p>本质是一个 int 型变量。在使用引用计数器时， 通常会将结构体 kref 嵌入到其他结构体中， 例如<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kobject.h#L72">struct kobject</a>， 以实现引用计数的管理。   </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105154248298.png" alt="image-20250105154248298" />

<p>为了实现引用计数功能， struct kobject 通常会包含一个嵌入的 struct kref 对象。 这样可以通过对 struct kref 的操作来对 struct kobject 进行引用计数的管理， 并在引用计数减少到 0 时释放相关资源。  </p>
<h2 id="3-相关API-1"><a href="#3-相关API-1" class="headerlink" title="3. 相关API"></a><font size=3>3. 相关API</font></h2><h3 id="3-1-kref-init"><a href="#3-1-kref-init" class="headerlink" title="3.1 kref_init()"></a><font size=3>3.1 kref_init()</font></h3><p> <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kref.h#L28">kref_init()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * kref_init - initialize object.</span></span><br><span class="line"><span class="comment"> * @kref: object in question.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">kref_init</span><span class="params">(<span class="keyword">struct</span> kref *kref)</span></span><br><span class="line">&#123;</span><br><span class="line">	refcount_set(&amp;kref-&gt;refcount, <span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>初始化一个 struct kref 对象。 在使用引用计数之前， 必须先调用此函数进行初始化。 初始化 kerf 的值为 1 。</p>
<h3 id="3-2-kref-get"><a href="#3-2-kref-get" class="headerlink" title="3.2 kref_get() "></a><font size=3>3.2 kref_get() </font></h3><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kref.h#L45">kref_get()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * kref_get - increment refcount for object.</span></span><br><span class="line"><span class="comment"> * @kref: object.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">kref_get</span><span class="params">(<span class="keyword">struct</span> kref *kref)</span></span><br><span class="line">&#123;</span><br><span class="line">	refcount_inc(&amp;kref-&gt;refcount);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>增加 struct kref 的引用计数。 每次调用此函数， 引用计数都会增加。 kref 计数值加 1 。</p>
<h3 id="3-3-kref-put"><a href="#3-3-kref-put" class="headerlink" title="3.3 kref_put()"></a><font size=3>3.3 kref_put()</font></h3><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kref.h#L67">kref_put()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">int</span> <span class="title function_">kref_put</span><span class="params">(<span class="keyword">struct</span> kref *kref, <span class="type">void</span> (*release)(<span class="keyword">struct</span> kref *kref))</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span> (refcount_dec_and_test(&amp;kref-&gt;refcount)) &#123;</span><br><span class="line">		release(kref);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>减少 struct kref 的引用计数， 并在引用计数减少到零时调用 release 函数来进行资源的释放。 通常， release 函数会在其中执行对象的销毁和内存释放等操作。  </p>
<h3 id="3-4-refcount-set"><a href="#3-4-refcount-set" class="headerlink" title="3.4 refcount_set()"></a><font size=3>3.4 refcount_set()</font></h3><p><a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/refcount.h#L25">refcount_set()</a> 定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * refcount_set - set a refcount&#x27;s value</span></span><br><span class="line"><span class="comment"> * @r: the refcount</span></span><br><span class="line"><span class="comment"> * @n: value to which the refcount will be set</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">refcount_set</span><span class="params">(<span class="type">refcount_t</span> *r, <span class="type">unsigned</span> <span class="type">int</span> n)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">atomic_set</span>(&amp;r-&gt;refs, n);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>设置 kerf 的计数值。  </p>
<h2 id="4-kref-demo"><a href="#4-kref-demo" class="headerlink" title="4. kref demo"></a><font size=3>4. kref demo</font></h2><h3 id="4-1-demo源码-1"><a href="#4-1-demo源码-1" class="headerlink" title="4.1 demo源码"></a><font size=3>4.1 demo源码</font></h3><p>可以看这里：<a target="_blank" rel="noopener" href="https://gitee.com/sumumm/imx6ull-driver-demo/tree/master/05_device_model/04_kref">05_device_model&#x2F;04_kref · 苏木&#x2F;imx6ull-driver-demo - 码云 - 开源中国</a></p>
<details class="folding-tag" blue><summary> 点击查看详情 </summary>
              <div class='content'>
              <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/init.h&gt;</span> <span class="comment">/* module_init module_exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span> <span class="comment">/* MODULE_LICENSE */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kobject.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./timestamp_autogenerated.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./version_autogenerated.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./sdrv_common.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// #undef PRT</span></span><br><span class="line"><span class="comment">// #undef PRTE</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> PRT</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PRT printk</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> PRTE</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PRTE printk</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义三个kobject指针变量：skobject1、skobject2、skobject3</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject1</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject2</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject3</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobj_type</span> <span class="title">stype</span> =</span> &#123;<span class="number">0</span>&#125;; <span class="comment">// 定义一个kobj_type结构体变量stype，用于描述kobject的类型。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  sdriver_demo_init()</span></span><br><span class="line"><span class="comment"> * @note   </span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> __init <span class="type">int</span> <span class="title function_">sdriver_demo_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	printk(<span class="string">&quot;*** [%s:%d]Build Time: %s %s, git version:%s ***\n&quot;</span>, __FUNCTION__,</span><br><span class="line">           __LINE__, KERNEL_KO_DATE, KERNEL_KO_TIME, KERNEL_KO_VERSION);</span><br><span class="line">    PRT(<span class="string">&quot;sdriver_demo module init!\n&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 创建kobject的第一种方法</span></span><br><span class="line">    <span class="comment">// 创建并添加一个名为&quot;skobject1&quot;的kobject对象，父kobject为NULL</span></span><br><span class="line">    skobject1 = kobject_create_and_add(<span class="string">&quot;skobject1&quot;</span>, <span class="literal">NULL</span>);</span><br><span class="line">    PRT(<span class="string">&quot;skobject1 kref is %d\n&quot;</span>, skobject1-&gt;kref.refcount.refs.counter);</span><br><span class="line">    <span class="comment">// 创建并添加一个名为&quot;skobject2&quot;的kobject对象，父kobject为skobject1。</span></span><br><span class="line">    skobject2 = kobject_create_and_add(<span class="string">&quot;skobject2&quot;</span>, skobject1);</span><br><span class="line">    PRT(<span class="string">&quot;skobject2 kref is %d\n&quot;</span>, skobject2-&gt;kref.refcount.refs.counter);</span><br><span class="line">    <span class="comment">// 创建kobject的第二种方法</span></span><br><span class="line">    <span class="comment">// 1.使用kzalloc函数分配了一个kobject对象的内存</span></span><br><span class="line">    skobject3 = kzalloc(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> kobject), GFP_KERNEL);</span><br><span class="line">    <span class="comment">// 2.初始化并添加到内核中，名为&quot;skobject3&quot;。</span></span><br><span class="line">    ret = kobject_init_and_add(skobject3, &amp;stype, <span class="literal">NULL</span>, <span class="string">&quot;%s&quot;</span>, <span class="string">&quot;skobject3&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        PRTE(<span class="string">&quot;kobject_init_and_add fail!ret=%d\n&quot;</span>, ret);</span><br><span class="line">        <span class="keyword">goto</span> err_kobject_init_and_add;</span><br><span class="line">    &#125;</span><br><span class="line">	PRT(<span class="string">&quot;skobject3 kref is %d\n&quot;</span>, skobject3-&gt;kref.refcount.refs.counter);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err_kobject_init_and_add:</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  sdriver_demo_exit()</span></span><br><span class="line"><span class="comment"> * @note   </span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> __exit <span class="type">void</span> <span class="title function_">sdriver_demo_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    PRT(<span class="string">&quot;skobject1 kref is %d\n&quot;</span>, skobject1-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;skobject2 kref is %d\n&quot;</span>, skobject2-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;skobject3 kref is %d\n&quot;</span>, skobject3-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;before kobject_put all!\n\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 释放之前创建的kobject对象</span></span><br><span class="line">    kobject_put(skobject1);</span><br><span class="line">    PRT(<span class="string">&quot;skobject1 kref is %d\n&quot;</span>, skobject1-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;skobject2 kref is %d\n&quot;</span>, skobject2-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;skobject3 kref is %d\n&quot;</span>, skobject3-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;after kobject_put skobject1!\n\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    kobject_put(skobject2);</span><br><span class="line">    PRT(<span class="string">&quot;skobject1 kref is %d\n&quot;</span>, skobject1-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;skobject2 kref is %d\n&quot;</span>, skobject2-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;skobject3 kref is %d\n&quot;</span>, skobject3-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;after kobject_put skobject2!\n\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    kobject_put(skobject3);</span><br><span class="line">    PRT(<span class="string">&quot;skobject1 kref is %d\n&quot;</span>, skobject1-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;skobject2 kref is %d\n&quot;</span>, skobject2-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;skobject3 kref is %d\n&quot;</span>, skobject3-&gt;kref.refcount.refs.counter);</span><br><span class="line">    PRT(<span class="string">&quot;after kobject_put skobject3!\n\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    PRT(<span class="string">&quot;sdriver_demo module exit!\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">module_init(sdriver_demo_init); <span class="comment">// 将__init定义的函数指定为驱动的入口函数</span></span><br><span class="line">module_exit(sdriver_demo_exit); <span class="comment">// 将__exit定义的函数指定为驱动的出口函数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 模块信息(通过 modinfo chrdev_led_demo 查看) */</span></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL v2&quot;</span>);            <span class="comment">/* 源码的许可证协议 */</span></span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;sumu&quot;</span>);               <span class="comment">/* 字符串常量内容为模块作者说明 */</span></span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;Description&quot;</span>);   <span class="comment">/* 字符串常量内容为模块功能说明 */</span></span><br><span class="line">MODULE_ALIAS(<span class="string">&quot;module&#x27;s other name&quot;</span>); <span class="comment">/* 字符串常量内容为模块别名 */</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="4-2-开发板验证-1"><a href="#4-2-开发板验证-1" class="headerlink" title="4.2 开发板验证"></a><font size=3>4.2 开发板验证</font></h3><p>我们把生成的驱动拷贝到开发板，然后加载，再卸载，可以看到计数值的变化情况：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105202747415.png" alt="image-20250105202747415" />

<p>驱动加载之后， 第一条打印为“skobject1 kref is 1”， 因为创建了 skobject1,所以引用计数器的值为 1， 如下图所示的（1）。 第二条打印为： “skobject1 kref is 2”， 因为在skobject1 目录下创建了子目录 skobject2，所以 skobject1 的计数器值为 2， skobject2 的计数器值为 1， 如下图所示的（2）。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105203726480.png" alt="image-20250105203726480" />

<p>可以扩展一下，加深理解：如上图（3）所示， 如果在 objectA 下面创建俩个 object， objectA 的 计数器值为 3。 如上图所示（4）， 如果在 objectA 下面创建两个 object， 那么 objectA 的计数器值 为 3， 在 objectB 下创建 object,那么 objectB 的计数器值为 2， objectC 的计数器值为 1。  </p>
<p>最后我们卸载驱动，当引用计数器的值为 0 时， 表示没有任何引用指向对象或资源， 可以安全地释放对象或资源， 并进行相关的清理操作。  </p>
<h1 id="五、ktype"><a href="#五、ktype" class="headerlink" title="五、ktype"></a><font size=3>五、ktype</font></h1><h2 id="1-kobj-type是什么"><a href="#1-kobj-type是什么" class="headerlink" title="1. kobj_type是什么"></a><font size=3>1. kobj_type是什么</font></h2><p>每个kobject对象都有一些属性，这些属性由kobj_type表示。kobj_type就是用于表征kobject的的一些属性，指定了删除kobject时要调用的函数，kobject结构体中有struct kref字段用于对kobject进行引用计数，当计数值为0时，就会调用kobj_type中的release函数对kobject进行释放，这个就有点类似于C++中的智能指针了；它还指定了通过sysfs显示或修改有关kobject的信息时要处理的操作，实际是调用show&#x2F;store函数。</p>
<p>kobj_type定义在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/kobject.h#L139">struct kobj_type</a> 中：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobj_type</span> &#123;</span></span><br><span class="line">	<span class="type">void</span> (*release)(<span class="keyword">struct</span> kobject *kobj);</span><br><span class="line">	<span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">sysfs_ops</span> *<span class="title">sysfs_ops</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">attribute</span> **<span class="title">default_attrs</span>;</span></span><br><span class="line">	<span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">kobj_ns_type_operations</span> *(*<span class="title">child_ns_type</span>)(<span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">kobj</span>);</span></span><br><span class="line">	<span class="type">const</span> <span class="type">void</span> *(*namespace)(<span class="keyword">struct</span> kobject *kobj);</span><br><span class="line">	<span class="type">void</span> (*get_ownership)(<span class="keyword">struct</span> kobject *kobj, <span class="type">kuid_t</span> *uid, <span class="type">kgid_t</span> *gid);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<ul>
<li>release：通过该回调函数，可以将包含该类型kobject的数据结构的内存空间释放掉。</li>
<li>sysfs_ops：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/sysfs.h#L214">struct sysfs_ops</a> 类型，该种类型的kobject的sysfs文件系统接口（读属性接口show及写属性接口store）。</li>
<li>default_attrs：<a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/include/linux/sysfs.h#L30">struct attribute</a> 类型，该种类型的kobject的atrribute列表（所谓attribute，就是sysfs文件系统中的一个文件）。将会在kobject添加到内核时，一并注册到sysfs中。</li>
<li>child_ns_type&#x2F;namespace：和文件系统（sysfs）的命名空间有关，这里不再详细说明。</li>
</ul>
<h2 id="2-ktype与kobject的关系"><a href="#2-ktype与kobject的关系" class="headerlink" title="2. ktype与kobject的关系"></a><font size=3>2. ktype与kobject的关系</font></h2><img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105200924853.png" alt="image-20250105200924853" />

<ul>
<li>kobject 在创建的时候，默认设置 kobj_type 的值为 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L719">dynamic_kobj_ktype</a>（在 <a target="_blank" rel="noopener" href="https://elixir.bootlin.com/linux/v4.19.71/source/lib/kobject.c#L743">kobject_create()</a> 函数中设置的），通常 kobject 会嵌入在其他结构中来使用，因此它的初始化跟特定的结构相关，典型的比如 struct device 和 struct device_driver ；</li>
<li>在 &#x2F;sys 文件系统中，通过 echo&#x2F;cat 的操作，最终会调用到 show&#x2F;store 函数，而这两个函数的具体实现可以放置到驱动程序中；</li>
</ul>
<h2 id="3-ktype-demo"><a href="#3-ktype-demo" class="headerlink" title="3. ktype demo"></a><font size=3>3. ktype demo</font></h2><h3 id="3-1-demo源码"><a href="#3-1-demo源码" class="headerlink" title="3.1 demo源码"></a><font size=3>3.1 demo源码</font></h3><p>可以看这里：<a target="_blank" rel="noopener" href="https://gitee.com/sumumm/imx6ull-driver-demo/tree/master/05_device_model/05_ktype">05_device_model&#x2F;05_ktype · 苏木&#x2F;imx6ull-driver-demo - 码云 - 开源中国</a></p>
<details class="folding-tag" blue><summary> 点击查看详情 </summary>
              <div class='content'>
              <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/init.h&gt;</span> <span class="comment">/* module_init module_exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span> <span class="comment">/* MODULE_LICENSE */</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kobject.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./timestamp_autogenerated.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./version_autogenerated.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./sdrv_common.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// #undef PRT</span></span><br><span class="line"><span class="comment">// #undef PRTE</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> PRT</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PRT printk</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> PRTE</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PRTE printk</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> *<span class="title">skobject1</span> =</span> <span class="literal">NULL</span>; <span class="comment">// 定义kobject指针变量：skobject1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  dynamic_kobj_release()</span></span><br><span class="line"><span class="comment"> * @note   定义kobject的释放函数</span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">dynamic_kobj_release</span><span class="params">(<span class="keyword">struct</span> kobject *kobj)</span></span><br><span class="line">&#123;</span><br><span class="line">    PRT(<span class="string">&quot;kobject: %p\n&quot;</span>, kobj);</span><br><span class="line">    kfree(kobj);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义了一个kobj_type结构体变量stype，用于描述kobject的类型。</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobj_type</span> <span class="title">stype</span> =</span> &#123;</span><br><span class="line">    .release = dynamic_kobj_release,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  sdriver_demo_init()</span></span><br><span class="line"><span class="comment"> * @note   </span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> __init <span class="type">int</span> <span class="title function_">sdriver_demo_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	printk(<span class="string">&quot;*** [%s:%d]Build Time: %s %s, git version:%s ***\n&quot;</span>, __FUNCTION__,</span><br><span class="line">           __LINE__, KERNEL_KO_DATE, KERNEL_KO_TIME, KERNEL_KO_VERSION);</span><br><span class="line">    PRT(<span class="string">&quot;sdriver_demo module init!\n&quot;</span>);</span><br><span class="line">    </span><br><span class="line"></span><br><span class="line">    <span class="comment">// 创建kobject的第二种方法</span></span><br><span class="line">    <span class="comment">// 1.使用kzalloc函数分配了一个kobject对象的内存</span></span><br><span class="line">    skobject1 = kzalloc(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> kobject), GFP_KERNEL);</span><br><span class="line">    <span class="comment">// 2.初始化并添加到内核中，名为&quot;skobject1&quot;。</span></span><br><span class="line">    ret = kobject_init_and_add(skobject1, &amp;stype, <span class="literal">NULL</span>, <span class="string">&quot;%s&quot;</span>, <span class="string">&quot;skobject1&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span>(ret &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        PRTE(<span class="string">&quot;kobject_init_and_add fail!ret=%d\n&quot;</span>, ret);</span><br><span class="line">        <span class="keyword">goto</span> err_kobject_init_and_add;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err_kobject_init_and_add:</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  sdriver_demo_exit()</span></span><br><span class="line"><span class="comment"> * @note   </span></span><br><span class="line"><span class="comment"> * @param [in]</span></span><br><span class="line"><span class="comment"> * @param [out]</span></span><br><span class="line"><span class="comment"> * @retval </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> __exit <span class="type">void</span> <span class="title function_">sdriver_demo_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">// 释放之前创建的kobject对象</span></span><br><span class="line">    kobject_put(skobject1);</span><br><span class="line">    PRT(<span class="string">&quot;sdriver_demo module exit!\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">module_init(sdriver_demo_init); <span class="comment">// 将__init定义的函数指定为驱动的入口函数</span></span><br><span class="line">module_exit(sdriver_demo_exit); <span class="comment">// 将__exit定义的函数指定为驱动的出口函数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 模块信息(通过 modinfo chrdev_led_demo 查看) */</span></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL v2&quot;</span>);            <span class="comment">/* 源码的许可证协议 */</span></span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;sumu&quot;</span>);               <span class="comment">/* 字符串常量内容为模块作者说明 */</span></span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;Description&quot;</span>);   <span class="comment">/* 字符串常量内容为模块功能说明 */</span></span><br><span class="line">MODULE_ALIAS(<span class="string">&quot;module&#x27;s other name&quot;</span>); <span class="comment">/* 字符串常量内容为模块别名 */</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="3-2-开发板验证"><a href="#3-2-开发板验证" class="headerlink" title="3.2 开发板验证"></a><font size=3>3.2 开发板验证</font></h3><p>我们拷贝到开发板，然后加载驱动，卸载驱动，这个实验主要是通过ktype自定义了kobject对象释放的时候的回调函数：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/02IMX6ULL%E5%B9%B3%E5%8F%B0/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/LV06-04-linux%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B-02-kobject%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/img/image-20250105224309104.png" alt="image-20250105224309104" />

<p>可以看到，当释放的时候，会出现我们的自定义打印信息。</p>
<blockquote>
<p>参考资料</p>
<p>【1】<a target="_blank" rel="noopener" href="https://blog.csdn.net/vincent3678/article/details/115284784">linux驱动开发—— 6、linux 设备驱动模型_什么是kobject-CSDN博客</a></p>
<p>【2】<a target="_blank" rel="noopener" href="https://blog.csdn.net/liangzc1124/article/details/127586874">Linux设备模型剖析系列一（基本概念、kobject、kset、kobj_type）_device下的kobj-CSDN博客</a></p>
<p>【3】<a target="_blank" rel="noopener" href="http://www.wowotech.net/device_model/13.html">Linux设备模型(1)_基本概念</a></p>
<p>【4】<a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_16504163/article/details/118562670">一张图掌握 Linux platform 平台设备驱动框架！【建议收藏】-CSDN博客</a></p>
<p>【5】<a target="_blank" rel="noopener" href="https://www.kernel.org/doc/html/latest/translations/zh_CN/core-api/kobject.html">关于kobjects、ksets和ktypes的一切你没想过需要了解的东西 — The Linux Kernel documentation</a></p>
<p>【6】<a target="_blank" rel="noopener" href="https://www.cnblogs.com/LoyenWang/p/13334196.html">【原创】linux设备模型之kset&#x2F;kobj&#x2F;ktype分析 - LoyenWang - 博客园</a></p>
<p>【7】<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/464481582">kobject &#x2F; kset &#x2F; ktype（linux kernel 中的面向对象） - 知乎</a></p>
</blockquote>

    </div>

    
    
    

    <footer class="post-footer">




    <div>
        
            <div style="text-align:center;color: #ccc;font-size:14px;">
            ----------本文结束
            <i class="fas fa-fan fa-spin" style="color: #FF1493; font-size: 1rem"></i>
            感谢您的阅读----------
            </div>
        
    </div>





  
  <div class="my_post_copyright"> 
    <p><span>文章标题:</span><a href="/post/5eede1d3.html">LV06-04-linux设备模型-02-kobject相关的数据结构</a></p>
    <p><span>文章作者:</span><a href="/" title="欢迎访问 《苏木》 的学习笔记">苏木</a></p>
    <p><span>发布时间:</span>2025年01月05日 - 22:46</p>
    <p><span>最后更新:</span>2025年06月14日 - 00:25</p>
    <p><span>原始链接:</span><a href="/post/5eede1d3.html" title="LV06-04-linux设备模型-02-kobject相关的数据结构">https://sumumm.github.io/post/5eede1d3.html</a></p>
    <p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="license" href= "https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a> 转载请保留原文链接及作者。</p>  
  </div>
  


          <div class="post-tags">
              <a href="/tags/LV06-%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91/" rel="tag"><i class="fa fa-tag"></i> LV06-驱动开发</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/post/d70fd185.html" rel="prev" title="LV06-04-linux设备模型-03-sysfs文件系统">
                  <i class="fa fa-angle-left"></i> LV06-04-linux设备模型-03-sysfs文件系统
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/post/8ee6048d.html" rel="next" title="LV06-03-chrdev-09-点亮LED-02-LED驱动框架">
                  LV06-03-chrdev-09-点亮LED-02-LED驱动框架 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2017 – 
    <span itemprop="copyrightYear">2025</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">苏木</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">3.7m</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">225:26</span>
  </span>
</div>




    <span id="sitetime"></span>
    <script defer language=javascript>
        function siteTime()
        {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth()+1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /*==================================================
            Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year        - 作为date对象的年份，为4位年份值
            month       - 0-11之间的整数，做为date对象的月份
            day         - 1-31之间的整数，做为date对象的天数
            hours       - 0(午夜24点)-23之间的整数，做为date对象的小时数
            minutes     - 0-59之间的整数，做为date对象的分钟数
            seconds     - 0-59之间的整数，做为date对象的秒数
            microseconds - 0-999之间的整数，做为date对象的毫秒数
            ==================================================*/
            var t1 = Date.UTC(2017, 
                              5, 
                              19, 
                              0, 
                              0, 
                              0); //北京时间
            var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
            var diff = t2-t1;
            var diffYears = Math.floor(diff/years);
            var diffDays = Math.floor((diff/days)-diffYears*365);
            var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
            var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
            var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
            document.getElementById("sitetime").innerHTML="已在这里 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
        }
        siteTime();
    </script>



    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js" integrity="sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>

  <script src="/js/third-party/pace.js"></script>


  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>


 
        <div id="click-show-text"
            data-mobile = false
            data-text = 富强,民主,文明,和谐,自由,平等,公正,法制,爱国,敬业,诚信,友善
            data-fontsize = 15px
            data-random= false>
        </div>
       

      
        <script async src=https://cdn.jsdelivr.net/npm/hexo-next-mouse-effect@latest/click/showText.js></script>
      

      
    




    <script async src="/js/fancybox_param.js"></script>





<!-- APlayer本体 -->



</body>
</html>
